今天居然是最後一天
來不及啦~
修改MemberService檔案加入UsernamePasswordAuthenticationToken
package com.tzu.service;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.tzu.domain.AppPrincipal;
import com.tzu.domain.AppUserHandler;
import com.tzu.domain.MemberJpaRepository;
@RestController
public class MemberService {
//注入依賴的Jpa
@Autowired
private MemberJpaRepository memberRepo;
//使用登入驗證作業
@GetMapping(path="/api/member/uservalid/{username}/{pwd}/rawdata",produces="application/json")
public Collection<? extends GrantedAuthority> userVaid(@PathVariable(name="username")String userName,@PathVariable(name="pwd")String password) {
//建構自訂UserDetailsService
AppUserHandler userService=new AppUserHandler();
Collection<? extends GrantedAuthority> authorties=null;
//注入Jap
userService.setMemberRepo(memberRepo);
//透過服務取出UserDetails物件
UserDetails userDetails=userService.loadUserByUsername(userName);
//進行雙重驗證
if(userDetails==null) {
//沒有這一個會員
}else {
//驗證密碼
if(password.equals(userDetails.getPassword())) {
//2.建構Principal(當事者)
AppPrincipal principal=new AppPrincipal(userDetails.getUsername());
//3.準備授權許可證(RBAC role base Access Control)
authorties=userDetails.getAuthorities();
//4.TODO 封裝當事者與使用者 與授權令牌Token 進入一個貫穿應用系統Context 正式的Token(令牌)
UsernamePasswordAuthenticationToken token=
new UsernamePasswordAuthenticationToken(
principal,
userDetails,
authorties
);
//5需要一個代表跟前端有關(透過Thread)封裝安全性資訊 可以貫穿整個應用系統
SecurityContext context=SecurityContextHolder.getContext();
//這一個Context帶相對令牌
context.setAuthentication(token);
System.out.println(context.getAuthentication().isAuthenticated());
}else {
//偽造身分
}
}
return authorties;
}
}
這段程式碼是一個Spring Boot應用程式的REST控制器 MemberService
,它負責處理HTTP GET請求以進行使用者的登入驗證。這個控制器透過 AppUserHandler
類別執行使用者的登入驗證,並執行以下操作:
UsernamePasswordAuthenticationToken
建立:在成功驗證使用者的登入後,它建立一個 UsernamePasswordAuthenticationToken
物件,這個物件包含了使用者的身份(principal
)、使用者的資訊(userDetails
)、以及授權許可證(authorities
)。
SecurityContext
設定:接著,它獲取目前的 SecurityContext
(安全性上下文),將建立的 UsernamePasswordAuthenticationToken
設定到 SecurityContext
中。這樣可以確保安全性資訊在整個應用程式中可被使用,並且可跨不同部分傳遞。
安全性檢查:最後,它檢查 SecurityContext
的驗證狀態,並列印出是否已經驗證成功。
總之,這個控制器 MemberService
負責處理使用者的登入驗證,並將相關的安全性資訊設定到 SecurityContext
中,以確保在應用程式中可以使用這些資訊來實現安全性控制。這是一個簡單的範例,實際上,通常會使用Spring Security來處理使用者的登入驗證,以及授權和身分驗證的設定。
用POSTMAN測試http://localhost:8080/api/member/uservalid/eric/1111/rawdata
後端顯示true
修改ApplictionConfig註解
package com.tzu.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import com.mysql.cj.jdbc.MysqlDataSource;
import com.tzu.beans.HelloBean;
import com.tzu.beans.HelloProxy;
import com.tzu.beans.IHello;
import com.tzu.beans.TWHello;
import com.tzu.domain.ApiKeyRepository;
import com.tzu.filter.ApiKeyFilter;
//透過方法生產Bean物件 註冊到Spring容器去
@EnableWebSecurity
@Configuration
public class ApplictionConfig {
//Attribute 使用spEL ${}
//@Value標註取出預設組態application.properties設定項目
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.username}")
private String userName;
@Value("${spring.datasource.password}")
private String password;
public ApplictionConfig() {
System.out.println("Configuration Bean配置了");
}
//生產一個HelloBean物件
@Bean(name="hellonean")
public HelloBean getHelloBean() {
System.out.println("Hello Bean產生了");
//建構HelloBean
HelloBean hello=new HelloBean();
return hello;
}
@Bean
public TWHello getTWHello() {
System.out.println("TW Hello Bean產生了");
//建構HelloBean
TWHello hello=new TWHello();
return hello;
}
//參數使用定義Bean alias Name 注入依賴 隨著窗口物件注入到對方去 進行反轉物件注入
@Bean
public HelloProxy getHelloProxy(TWHello bean) {
var helloProxy=new HelloProxy(bean);
return helloProxy;
}
//產生一個DataSource 是共用的物件(連接物件工廠 整個應用系統工廠只要一個即可)
@Bean
@Scope("singleton")
public DataSource createDataSource() {
System.out.println("Datasource:"+this.url);
//建構MySQLDataSource
MysqlDataSource datasource=new MysqlDataSource();
//配置要件 URL/User name/password
datasource.setUrl(url);
datasource.setUser(userName);
datasource.setPassword(password);
//Driver 會進行內部使用
return datasource;
}
//生產JdbcTemplate元件(Spring Bean)
//透過IoC注入控制反轉 注入DataSource物件
@Bean //生命週期每一個注入 產生一個體
public JdbcTemplate createJdbcTemplate(DataSource datasource) {
//建構JdbcTemplate物件
System.out.println("JdbcTemplate 注入的DataSource:"+datasource.toString());
JdbcTemplate template=new JdbcTemplate();
template.setDataSource(datasource); //Property Injection屬性注入依賴物件
return template;
}
//註冊Filter bean 進入Spring Container
//使用IoC 注入控制反轉 注入需要JpaRepository
@Bean
public FilterRegistrationBean<ApiKeyFilter> apikeyFilter(ApiKeyRepository reposit) {
System.out.println("註冊Filter攔截器 ApiKeyFilter..."+reposit);
FilterRegistrationBean<ApiKeyFilter> register=
new FilterRegistrationBean<>();
var filter=new ApiKeyFilter();
filter.setReposit(reposit); //透過Property Injection
register.setFilter(filter); //註冊Filter
//設定url pattern
register.addUrlPatterns("/api/customers/*"); //設定Filter UrlPattern 攔截起來的端點
return register;
}
//產生Web Security Config
//使用注入控制反轉 (IoC)
@Bean
public SecurityFilterChain configSecurity(HttpSecurity http) {
System.out.println(http.toString());
//設定CSRF 安全性 產生403 status
SecurityFilterChain chain=null;
try {
http.csrf()
.and()
.formLogin().loginPage("/mylogin")
.and()
.securityMatcher("/customers/*")
.authorizeHttpRequests()
.requestMatchers("/","/mylogin","/api/hello/**","/api/member/**").permitAll() //允許匿名存取(只允許網站入口-首頁/燈入頁面
.requestMatchers("/css/**","/html/**","/js/**","/ui/**").permitAll(); //針對static file允續匿名存取
//.anyRequest()
//authenticated(); //調用到登入頁面 登入頁面並沒有匿名存取 又要求到自己一次....
//... 匿名存取網站 通通可以通行
//透過HttpSecurity Builder(工廠)生產出SecurityFilterChain
chain=http.build();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
return chain;
}
}
這段程式碼是一個 Spring Boot 應用程式的配置類別 ApplictionConfig
,它使用了 @Configuration
標註,表示它是一個配置類別,它主要負責配置應用程式的一些核心設定,包括資料庫連接、Bean 的創建、Filter 的設定以及 Spring Security 的配置。
以下是這個配置類別的主要內容:
屬性配置: 使用 @Value
標註來讀取 application.properties
中的設定項目,包括資料庫的 URL、使用者名稱和密碼。
Bean 的配置: 定義了多個 Bean,例如 HelloBean
、TWHello
、HelloProxy
,並使用 @Bean
標註來將這些 Bean 注入到 Spring 容器中,以供其他元件使用。
資料庫連接設定: 透過 MysqlDataSource
類別建立資料庫連接,並設定資料庫的 URL、使用者名稱和密碼。這個資料庫連接可以透過 DataSource
Bean 來存取。
JdbcTemplate 配置: 使用 JdbcTemplate
來操作資料庫,透過 createJdbcTemplate
方法配置 JdbcTemplate
Bean,並注入 DataSource
依賴。
Filter 設定: 透過 FilterRegistrationBean
設定了一個名為 ApiKeyFilter
的過濾器,並將其加入 Spring 容器。這個過濾器將攔截 /api/customers/*
端點的請求。
Spring Security 配置: 透過 SecurityFilterChain
的 configSecurity
方法配置 Spring Security,包括 CSRF 安全性設定、登入頁面的設定、URL 的許可和拒絕訪問等。
總之,這個配置類別主要負責應用程式的核心設定,包括資料庫連接、Bean 的配置、過濾器的設定和 Spring Security 的配置。這些設定將對整個應用程式的運作和安全性產生影響。
修改FormController.java檔案
package com.tzu.controllers;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.tzu.domain.AppPrincipal;
import com.tzu.domain.AppUserHandler;
import com.tzu.domain.MemberJpaRepository;
@Controller
public class FormController {
@Autowired
private MemberJpaRepository memberRepo;
@RequestMapping(path="/mylogin",method= {RequestMethod.GET,RequestMethod.POST})
public String login(String userName,String password) {
//第一次請求
if(userName==null) {
return "login";
}else
{
System.out.println(userName);
//TODO 進行登入驗證
isValid(userName,password);
return "login";
}
}
//進行安全性驗證
@RequestMapping(path="/mylogin/uservalid",method= {RequestMethod.POST,RequestMethod.GET})
public String userValid(String userName,String password) {
System.out.println("登入帳號:"+userName);
//進行使用者驗證
//安全性設定(Identity/Roles/Principal/ Context...
return "ok";
}
public boolean isValid(String userName,String password) {
//建構自訂UserDetailsService
AppUserHandler userService=new AppUserHandler();
Collection<? extends GrantedAuthority> authorties=null;
//注入Jap
userService.setMemberRepo(memberRepo);
//透過服務取出UserDetails物件
UserDetails userDetails=userService.loadUserByUsername(userName);
//進行雙重驗證
if(userDetails==null) {
//沒有這一個會員
}else {
//驗證密碼
if(password.equals(userDetails.getPassword())) {
//2.建構Principal(當事者)
AppPrincipal principal=new AppPrincipal(userDetails.getUsername());
//3.準備授權許可證(RBAC role base Access Control)
authorties=userDetails.getAuthorities();
//4.TODO 封裝當事者與使用者 與授權令牌Token 進入一個貫穿應用系統Context 正式的Token(令牌)
UsernamePasswordAuthenticationToken token=
new UsernamePasswordAuthenticationToken(
principal,
userDetails,
authorties
);
//5需要一個代表跟前端有關(透過Thread)封裝安全性資訊 可以貫穿整個應用系統
SecurityContext context=SecurityContextHolder.getContext();
//這一個Context帶相對令牌
context.setAuthentication(token);
System.out.println(context.getAuthentication().isAuthenticated());
}else {
//偽造身分
}
}
return true;
}
}
這個程式碼片段是一個 Spring MVC 控制器類別 FormController
,它負責處理與使用者登入相關的請求。以下是這個控制器的主要內容:
依賴注入: 使用 @Autowired
注解來注入 MemberJpaRepository
,這個儲存庫用於存取會員資料。
login
方法: 這是一個請求映射方法,處理 /mylogin
端點的 GET 和 POST 請求。當用戶首次請求 /mylogin
時,此方法會返回 "login" 字串,將用戶導向登入頁面。當用戶提交表單(POST 請求)時,將調用 isValid
方法進行身份驗證並再次返回 "login",這將維持用戶在登入頁面。此方法可允許用戶輸入用戶名和密碼以進行身份驗證。
userValid
方法: 這是一個請求映射方法,處理 /mylogin/uservalid
端點的 POST 和 GET 請求。這個方法是似乎未使用的,因為它只返回 "ok" 字串,並沒有進行任何特定的身份驗證。
isValid
方法: 這個方法執行實際的身份驗證工作。它接受用戶名和密碼,然後使用 AppUserHandler
服務進行身份驗證。如果身份驗證成功,它將建構一個 AppPrincipal
(當事者)物件,並封裝使用者的身份和授權。然後,它建立一個 UsernamePasswordAuthenticationToken
來封裝這些信息,並將其設置到 Spring Security 的 SecurityContext
中,以確保安全性上下文保持一致。最後,它返回 true
來指示身份驗證成功。
總之,這個控制器主要處理用戶登入的相關操作,包括驗證用戶身份、將安全性上下文設定為已驗證狀態,並確保用戶保持在登入頁面上。這個控制器可能需要進一步的改進和修正以實現預期的功能。
測試瀏覽器http://localhost:8080/
測試登入http://localhost:8080/mylogin
後端顯示true
下一步,您可以考慮以下事情,根據您的應用程序需求和目標:
完善身份驗證和授權機制: 您已經開始實施用戶身份驗證,但可以考慮進一步加強授權機制。確保只有授權用戶能夠訪問特定資源和功能。
實施使用者註冊和密碼重設功能: 如果應用程序需要,您可以創建使用者註冊流程,以便新用戶可以註冊帳戶。同時,實施密碼重設機制以允許用戶在忘記密碼時重設它。
實現會員資料管理: 如果您的應用需要用戶設定個人資料或管理會員資訊,則可以建立相關功能。
加強安全性: 考慮實施其他安全性功能,如防止跨站腳本(XSS)攻擊、跨站請求偽造(CSRF)防護等。
實施前端界面: 創建用戶友好的前端界面,以便用戶可以舒適地使用您的應用程序。您可以使用前端框架如React、Angular或Vue.js。
整合其他功能: 根據應用程序需求,考慮整合其他功能,如電子郵件通知、支付處理、社交媒體分享等。
進行單元測試和端對端測試: 確保您的應用程式經過測試,以確保其正確性和安全性。
部署和監控: 將您的應用程式部署到生產環境中,然後設置監控和日誌記錄來跟蹤應用程式的性能和問題。
文件: 創建詳細的文件,以便開發人員、測試人員和最終用戶可以了解應用程式的使用和配置。
維護和更新: 持續監視您的應用程式,進行維護、修復錯誤和進行更新,以確保應用程序的順利運行。
當您開發一個複雜的應用程式時,通常建立一個良好的專案架構和文件對於確保代碼的組織和易於維護非常重要。這是一個簡單的建議專案結構,以幫助您開始:
my-application/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com/
│ │ │ │ ├── yourcompany/
│ │ │ │ │ ├── controllers/
│ │ │ │ │ │ ├── HomeController.java
│ │ │ │ │ ├── services/
│ │ │ │ │ │ ├── UserService.java
│ │ ├── resources/
│ │ │ ├── static/
│ │ │ │ ├── css/
│ │ │ │ ├── js/
│ │ │ │ ├── images/
│ │ │ ├── templates/
│ │ ├── application.properties
├── test/
│ ├── java/
│ │ ├── com/
│ │ │ ├── yourcompany/
│ │ │ │ ├── controllers/
│ │ │ │ │ ├── HomeControllerTest.java
├── pom.xml
這只是一個簡單的示例,專案結構取決於您的具體需求和技術選擇。下面是一些常見的目錄和文件,您可能需要考慮添加到您的專案:
controllers/:包含處理HTTP請求的控制器類。
services/:包含應用程序業務邏輯的服務類。
repositories/:包含數據存儲庫或數據訪問層(例如,JPA存儲庫)的類。
models/:包含應用程序數據模型或實體類的地方。
config/:包含應用程序配置類的目錄。
security/:包含安全性配置和用戶身份驗證的類。
resources/static/:包含CSS、JavaScript和其他前端資源的目錄。
resources/templates/:包含Thymeleaf或其他模板引擎模板的目錄。
test/:包含單元測試和端對端測試的目錄。
application.properties:應用程序的配置屬性。
pom.xml:Maven專案文件,用於管理依賴項和構建設定。
以上只是一些基本結構的示例,實際結構會根據您的專案需求而有所不同。您也可以考慮使用Spring Boot Initializer或其他專案生成工具,來生成適合特定技術堆棧的專案結構。這些工具通常會自動生成項目結構,以滿足最佳實踐和標準。
要實現成功的登入功能,您需要進行以下修改和添加:
使用Spring Security:Spring Security是實現身份驗證和授權的強大框架。首先,確保您的專案中已經包含Spring Security的相關依賴項。
配置Spring Security:您需要為Spring Security設置配置文件,指定哪些URL需要驗證,設置自訂的登入頁面,並配置用戶驗證的方法。您已經在您的代碼中進行了一些相關配置,確保您瞭解這些配置。
實現自訂的UserDetailsService:您的自訂AppUserHandler
實現了UserDetailsService
介面,這是用於查找和驗證用戶的關鍵部分。確保該類能夠正確查找用戶並檢查其密碼。
建立自訂的登入頁面:您需要建立一個自訂的登入頁面,通常位於resources/templates/
目錄下。這個頁面需要包含用戶名和密碼輸入字段以及登入按鈕。在提交表單時,它應該將用戶名和密碼發送到Spring Security的登入端點。
實現自訂的Controller:您的FormController
應該包含用於處理登入頁面的GET和POST請求的方法。當用戶提交登入表單時,POST方法應該調用Spring Security的驗證流程。
設置Spring Security成功和失敗處理程序:在Spring Security配置中,您可以設置成功登入後的處理程序和失敗登入後的處理程序。成功處理程序可能是將用戶重定向到應用程序的首頁,而失敗處理程序可能是在登入頁面上顯示錯誤消息。
添加登出功能:除了登入,您可能還需要實現登出功能。Spring Security提供了一個簡單的方式來實現登出。
授權訪問權限:一旦用戶成功登入,您可以配置Spring Security來設置哪些URL需要哪些權限才能訪問。這通常包括角色或權限的設置。
設置CSRF保護:確保您的應用程序受到跨站請求偽造(CSRF)的保護。Spring Security通常默認提供這種保護,但您應該確保它已經啟用。
以上是實現登入功能的一些基本步驟。確保您的Spring Security配置和自訂代碼能夠協同工作,以實現您的身份驗證需求。同時,根據您的應用程序需求和安全性要求,可能需要進一步的設定和調整。
當登入成功後,您通常會執行以下操作之一或多個,根據您的應用程序需求:
重定向到首頁或授權後的頁面:將用戶重定向到應用程序的首頁或他們之前正在訪問的頁面。這通常是最常見的操作。
顯示用戶的個人信息:如果您的應用程序具有用戶配置文件或個人信息頁面,則可以在登入成功後將用戶重定向到該頁面,以便他們查看或編輯其個人信息。
歡迎消息:顯示一個歡迎消息,向用戶表示登入成功。這可以是一個簡單的對話框或頁面上的消息。
登入日誌記錄:對登入成功的情況進行記錄,以供安全監控或審計目的使用。
啟動用戶的會話:在登入成功後,創建或啟動用戶的會話,以維護其身份信息和其他狀態。這有助於在會話中跟踪用戶的活動。
設置安全性上下文:在Spring Security中,已經在前面的代碼中設置了安全性上下文。此上下文應包含已驗證用戶的信息,並且該上下文可供整個應用程序使用。
您可以根據您的應用程序需求選擇以上操作之一或多個,或者自行定義其他自訂操作。請確保您的操作符合您的應用程序的用戶體驗和安全性要求。
部署一個應用程序可能涉及多個步驟,具體的步驟取決於您的應用程序類型、技術堆棧和部署環境。以下是一個簡要的通用指南,可以幫助您開始部署您的應用程序:
準備部署環境:
編譯/打包應用程序:
配置應用程序:
數據庫準備:
伺服器設置:
部署應用程序:
設置網絡和安全性:
監視和測試:
執行備份:
上線:
持續監控和維護:
縮放:
以上步驟是一個簡要的部署流程,
https://www.bezkoder.com/spring-boot-vue-js-mysql/#Spring_Boot_Vuejs_MySQL_Architecture
英文好的可以先看看
今年的投稿因為時間不夠GG
2024年再挑戰一次GOGO
謝謝大家收看